//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.github.pagehelper.page;

import com.github.pagehelper.AutoDialect;
import com.github.pagehelper.Dialect;
import com.github.pagehelper.PageException;
import com.github.pagehelper.PageProperties;
import com.github.pagehelper.dialect.AbstractHelperDialect;
import com.github.pagehelper.dialect.auto.C3P0AutoDialect;
import com.github.pagehelper.dialect.auto.DataSourceNegotiationAutoDialect;
import com.github.pagehelper.dialect.auto.DbcpAutoDialect;
import com.github.pagehelper.dialect.auto.DefaultAutoDialect;
import com.github.pagehelper.dialect.auto.DruidAutoDialect;
import com.github.pagehelper.dialect.auto.HikariAutoDialect;
import com.github.pagehelper.dialect.auto.TomcatAutoDialect;
import com.github.pagehelper.dialect.helper.AS400Dialect;
import com.github.pagehelper.dialect.helper.Db2Dialect;
import com.github.pagehelper.dialect.helper.FirebirdDialect;
import com.github.pagehelper.dialect.helper.HerdDBDialect;
import com.github.pagehelper.dialect.helper.HsqldbDialect;
import com.github.pagehelper.dialect.helper.InformixDialect;
import com.github.pagehelper.dialect.helper.MySqlDialect;
import com.github.pagehelper.dialect.helper.Oracle9iDialect;
import com.github.pagehelper.dialect.helper.OracleDialect;
import com.github.pagehelper.dialect.helper.OscarDialect;
import com.github.pagehelper.dialect.helper.PostgreSqlDialect;
import com.github.pagehelper.dialect.helper.SqlServer2012Dialect;
import com.github.pagehelper.dialect.helper.SqlServerDialect;
import com.github.pagehelper.util.StringUtil;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import javax.sql.DataSource;
import org.apache.ibatis.mapping.MappedStatement;

/**
 * 处理pagehelper-spring-boot-starter 1.4.6版本不适配kingbase8
 *
 * @Author 湖南佐佑时代科技有限公司（https://www.zuoyo.com）
 * @Version V5.4.21
 * @Email service@zuoyo.com
 * @Date 2023/03/16
 */
public class PageAutoDialect {
    private static Map<String, Class<? extends Dialect>> dialectAliasMap = new HashMap();
    private static Map<String, Class<? extends AutoDialect>> autoDialectMap = new HashMap();
    private boolean autoDialect = true;
    private Properties properties;
    private Map<Object, AbstractHelperDialect> urlDialectMap = new ConcurrentHashMap();
    private ReentrantLock lock = new ReentrantLock();
    private AbstractHelperDialect delegate;
    private ThreadLocal<AbstractHelperDialect> dialectThreadLocal = new ThreadLocal();
    private AutoDialect autoDialectDelegate;

    public PageAutoDialect() {
    }

    public static void registerDialectAlias(String alias, Class<? extends Dialect> dialectClass) {
        dialectAliasMap.put(alias, dialectClass);
    }

    public static void registerAutoDialectAlias(String alias, Class<? extends AutoDialect> autoDialectClass) {
        autoDialectMap.put(alias, autoDialectClass);
    }

    public static String fromJdbcUrl(String jdbcUrl) {
        String url = jdbcUrl.toLowerCase();
        Iterator var2 = dialectAliasMap.keySet().iterator();

        String dialect;
        do {
            if (!var2.hasNext()) {
                return null;
            }

            dialect = (String)var2.next();
        } while(!url.contains(":" + dialect.toLowerCase() + ":"));

        return dialect;
    }

    public AbstractHelperDialect getDelegate() {
        return this.delegate != null ? this.delegate : (AbstractHelperDialect)this.dialectThreadLocal.get();
    }

    public void clearDelegate() {
        this.dialectThreadLocal.remove();
    }

    public static Class resloveDialectClass(String className) throws Exception {
        return dialectAliasMap.containsKey(className.toLowerCase()) ? (Class)dialectAliasMap.get(className.toLowerCase()) : Class.forName(className);
    }

    public static AbstractHelperDialect instanceDialect(String dialectClass, Properties properties) {
        if (StringUtil.isEmpty(dialectClass)) {
            throw new PageException("使用 PageHelper 分页插件时，必须设置 helper 属性");
        } else {
            AbstractHelperDialect dialect;
            try {
                Class sqlDialectClass = resloveDialectClass(dialectClass);
                if (!AbstractHelperDialect.class.isAssignableFrom(sqlDialectClass)) {
                    throw new PageException("使用 PageHelper 时，方言必须是实现 " + AbstractHelperDialect.class.getCanonicalName() + " 接口的实现类!");
                }

                dialect = (AbstractHelperDialect)sqlDialectClass.newInstance();
            } catch (Exception var4) {
                throw new PageException("初始化 helper [" + dialectClass + "]时出错:" + var4.getMessage(), var4);
            }

            dialect.setProperties(properties);
            return dialect;
        }
    }

    public void initDelegateDialect(MappedStatement ms, String dialectClass) {
        if (StringUtil.isNotEmpty(dialectClass)) {
            AbstractHelperDialect dialect = (AbstractHelperDialect)this.urlDialectMap.get(dialectClass);
            if (dialect == null) {
                this.lock.lock();

                try {
                    if ((dialect = (AbstractHelperDialect)this.urlDialectMap.get(dialectClass)) == null) {
                        dialect = instanceDialect(dialectClass, this.properties);
                        this.urlDialectMap.put(dialectClass, dialect);
                    }
                } finally {
                    this.lock.unlock();
                }
            }

            this.dialectThreadLocal.set(dialect);
        } else if (this.delegate == null) {
            if (this.autoDialect) {
                this.delegate = this.autoGetDialect(ms);
            } else {
                this.dialectThreadLocal.set(this.autoGetDialect(ms));
            }
        }

    }

    public AbstractHelperDialect autoGetDialect(MappedStatement ms) {
        DataSource dataSource = ms.getConfiguration().getEnvironment().getDataSource();
        Object dialectKey = this.autoDialectDelegate.extractDialectKey(ms, dataSource, this.properties);
        if (dialectKey == null) {
            return this.autoDialectDelegate.extractDialect(dialectKey, ms, dataSource, this.properties);
        } else {
            if (!this.urlDialectMap.containsKey(dialectKey)) {
                this.lock.lock();

                try {
                    if (!this.urlDialectMap.containsKey(dialectKey)) {
                        this.urlDialectMap.put(dialectKey, this.autoDialectDelegate.extractDialect(dialectKey, ms, dataSource, this.properties));
                    }
                } finally {
                    this.lock.unlock();
                }
            }

            return (AbstractHelperDialect)this.urlDialectMap.get(dialectKey);
        }
    }

    private void initAutoDialectClass(Properties properties) {
        String autoDialectClassStr = properties.getProperty("autoDialectClass");
        if (StringUtil.isNotEmpty(autoDialectClassStr)) {
            try {
                Class autoDialectClass;
                if (autoDialectMap.containsKey(autoDialectClassStr)) {
                    autoDialectClass = (Class)autoDialectMap.get(autoDialectClassStr);
                } else {
                    autoDialectClass = Class.forName(autoDialectClassStr);
                }

                this.autoDialectDelegate = (AutoDialect)autoDialectClass.getConstructor().newInstance();
                if (this.autoDialectDelegate instanceof PageProperties) {
                    ((PageProperties)this.autoDialectDelegate).setProperties(properties);
                }
            } catch (ClassNotFoundException var4) {
                throw new IllegalArgumentException("请确保 autoDialectClass 配置的 AutoDialect 实现类(" + autoDialectClassStr + ")存在!", var4);
            } catch (Exception var5) {
                throw new RuntimeException(autoDialectClassStr + " 类必须提供无参的构造方法", var5);
            }
        } else {
            this.autoDialectDelegate = new DataSourceNegotiationAutoDialect();
        }

    }

    private void initDialectAlias(Properties properties) {
        String dialectAlias = properties.getProperty("dialectAlias");
        if (StringUtil.isNotEmpty(dialectAlias)) {
            String[] alias = dialectAlias.split(";");

            for(int i = 0; i < alias.length; ++i) {
                String[] kv = alias[i].split("=");
                if (kv.length != 2) {
                    throw new IllegalArgumentException("dialectAlias 参数配置错误，请按照 alias1=xx.dialectClass;alias2=dialectClass2 的形式进行配置!");
                }

                for(int j = 0; j < kv.length; ++j) {
                    try {
                        Class<? extends Dialect> diallectClass = (Class<? extends Dialect>) Class.forName(kv[1]);
                        registerDialectAlias(kv[0], diallectClass);
                    } catch (ClassNotFoundException var8) {
                        throw new IllegalArgumentException("请确保 dialectAlias 配置的 Dialect 实现类存在!", var8);
                    }
                }
            }
        }

    }

    public void setProperties(Properties properties) {
        this.initAutoDialectClass(properties);
        String useSqlserver2012 = properties.getProperty("useSqlserver2012");
        if (StringUtil.isNotEmpty(useSqlserver2012) && Boolean.parseBoolean(useSqlserver2012)) {
            registerDialectAlias("sqlserver", SqlServer2012Dialect.class);
            registerDialectAlias("sqlserver2008", SqlServerDialect.class);
        }

        this.initDialectAlias(properties);
        String dialect = properties.getProperty("helperDialect");
        String runtimeDialect = properties.getProperty("autoRuntimeDialect");
        if (StringUtil.isNotEmpty(runtimeDialect) && "TRUE".equalsIgnoreCase(runtimeDialect)) {
            this.autoDialect = false;
            this.properties = properties;
        } else if (StringUtil.isEmpty(dialect)) {
            this.autoDialect = true;
            this.properties = properties;
        } else {
            this.autoDialect = false;
            this.delegate = instanceDialect(dialect, properties);
        }

    }

    static {
        registerDialectAlias("hsqldb", HsqldbDialect.class);
        registerDialectAlias("h2", HsqldbDialect.class);
        registerDialectAlias("phoenix", HsqldbDialect.class);
        registerDialectAlias("postgresql", PostgreSqlDialect.class);
        registerDialectAlias("mysql", MySqlDialect.class);
        registerDialectAlias("mariadb", MySqlDialect.class);
        registerDialectAlias("sqlite", MySqlDialect.class);
        registerDialectAlias("herddb", HerdDBDialect.class);
        registerDialectAlias("oracle", OracleDialect.class);
        registerDialectAlias("oracle9i", Oracle9iDialect.class);
        registerDialectAlias("db2", Db2Dialect.class);
        registerDialectAlias("as400", AS400Dialect.class);
        registerDialectAlias("informix", InformixDialect.class);
        registerDialectAlias("informix-sqli", InformixDialect.class);
        registerDialectAlias("sqlserver", SqlServerDialect.class);
        registerDialectAlias("sqlserver2012", SqlServer2012Dialect.class);
        registerDialectAlias("derby", SqlServer2012Dialect.class);
        registerDialectAlias("dm", OracleDialect.class);
        registerDialectAlias("edb", OracleDialect.class);
        registerDialectAlias("oscar", OscarDialect.class);
        registerDialectAlias("clickhouse", MySqlDialect.class);
        registerDialectAlias("highgo", HsqldbDialect.class);
        registerDialectAlias("xugu", HsqldbDialect.class);
        registerDialectAlias("impala", HsqldbDialect.class);
        registerDialectAlias("firebirdsql", FirebirdDialect.class);
        registerDialectAlias("kingbase", PostgreSqlDialect.class);
        // 人大金仓新版本kingbase8
        registerDialectAlias("kingbase8", PostgreSqlDialect.class);
        registerAutoDialectAlias("old", DefaultAutoDialect.class);
        registerAutoDialectAlias("hikari", HikariAutoDialect.class);
        registerAutoDialectAlias("druid", DruidAutoDialect.class);
        registerAutoDialectAlias("tomcat-jdbc", TomcatAutoDialect.class);
        registerAutoDialectAlias("dbcp", DbcpAutoDialect.class);
        registerAutoDialectAlias("c3p0", C3P0AutoDialect.class);
        registerAutoDialectAlias("default", DataSourceNegotiationAutoDialect.class);
    }
}
